home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / Replacements / shell_1_0.lha / shell-1.0 / src / for.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-07  |  8.1 KB  |  388 lines

  1. /* for utility
  2.  
  3.     FOR var IN list DO cmd_list DONE
  4.  
  5.   list may contain wildcards
  6.   cmd_list is a semicolon separated list of commands with options
  7.     (and $var). Several commands may be included in () to execute them
  8.     in a subshell. The command CD is handled in a special way.
  9.  
  10.   The following two lines are equal
  11.  
  12.     FOR dir IN dir1 dir2 dir2 DO cd $dir ";" dir ";" cd / DONE
  13.     FOR dir IN dir1 dir2 dir2 DO ( cd $dir ";" dir ) DONE
  14. */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <exec/memory.h>
  21. #include <dos/dos.h>
  22. #include <dos/dostags.h>
  23. #include <dos/dosasl.h>
  24. #include <proto/exec.h>
  25. #include <proto/dos.h>
  26.  
  27. #include "util.h"
  28.  
  29. #define FULLPATHSIZE        1024L
  30. #define ANCHORSIZE        (sizeof (struct AnchorPath) + FULLPATHSIZE)
  31.  
  32. static int show_debug;
  33.  
  34. int for_command (int, char **);
  35. int cd_command (char *);
  36. int execute_commands (int, char **);
  37.  
  38. /* Remember the current dir and start the first level of FOR */
  39. int main (int argc, char ** argv)
  40. {
  41.     int status;
  42.     BPTR cd, orig;
  43.  
  44.     if (!(cd = Lock ("", SHARED_LOCK)) )
  45.     {
  46.     PrintFault (IoErr(), "FOR: Cannot lock current directory");
  47.     return 20;
  48.     }
  49.  
  50.     orig = CurrentDir (cd);
  51.  
  52.     status = for_command (argc, argv);
  53.  
  54.     UnLock (CurrentDir (orig));
  55.  
  56.     return status;
  57. }
  58.  
  59. /* Set a local variable according to a list of patterns and execute a
  60.     list of commands with each pattern */
  61. int for_command (int argc, char ** argv)
  62. {
  63.     char * var;
  64.     char * pat;
  65.     int first_pat, last_pat;
  66.     int first_cmd, last_cmd;
  67.     int t, level, len, has_wild;
  68.     int status = 0;
  69.  
  70.     /* There have to be 5 args min: FOR var IN DO DONE */
  71.     if (argc < 5 || argv[1][0] == '?')
  72.     {
  73. show_usage:
  74.     puts ("Usage: FOR var IN list DO cmd_list DONE");
  75.     return 10;
  76.     }
  77.  
  78.     t = 1;
  79.  
  80.     /* Enable debugging */
  81.     if (argv[t][0] == '-' && argv[t][1] == 'd')
  82.     {
  83.     show_debug = 1;
  84.     t ++;
  85.     }
  86.  
  87.     /* Read name of variable */
  88.     var = argv[t ++];
  89.  
  90.     /* Show it, if neccessary */
  91.     if (show_debug)
  92.     printf ("Var=\"%s\"\n", var);
  93.  
  94.     /* Now IN must follow */
  95.     if (strcmpi (argv[t], "IN"))
  96.     {
  97.     fprintf (stderr, "FOR: Missing IN\n");
  98.     goto show_usage;
  99.     }
  100.  
  101.     t ++;
  102.  
  103.     /* This is the start of the patterns */
  104.     first_pat = t;
  105.  
  106.     /* Search until the end of arguments or DO is found */
  107.     while (t<argc && strcmpi (argv[t],"DO"))
  108.     t ++;
  109.  
  110.     /* If we ran out of arguments, this is an error */
  111.     if (t == argc)
  112.     {
  113.     fprintf (stderr, "FOR: Missing DO\n");
  114.     goto show_usage;
  115.     }
  116.  
  117.     /* Set the end of patterns to the pre-last visited arg */
  118.     last_pat = t-1;
  119.  
  120.     /* If the last pattern is ";" (like in the bourne shell), ignore it */
  121.     if (argv[last_pat][0] == ';' && !argv[last_pat][1])
  122.     last_pat--;
  123.  
  124.     /* If there are no patterns, don't do anything (this is NO error !) */
  125.     if (last_pat < first_pat)
  126.     return 0;
  127.  
  128.     /* Skip DO */
  129.     t ++;
  130.  
  131.     /* If the first command is ";" (like in the bourne shell), ignore it */
  132.     if (argv[t][0] == ';' && !argv[t][1])
  133.     t ++;
  134.  
  135.     /* Now check the rest of the line. The current position is the first
  136.        command to execute */
  137.     first_cmd = t;
  138.  
  139.     /* Search until the end of arguments or DONE is found and that DONE
  140.     belongs to the current FOR */
  141.     level = 0;
  142.     while (t<argc)
  143.     {
  144.     if (!strcmpi (argv[t], "FOR"))
  145.         level ++;
  146.     else if (!strcmpi (argv[t], "DONE"))
  147.     {
  148.         if (!level)
  149.         break;
  150.  
  151.         level --;
  152.     }
  153.  
  154.     t ++;
  155.     }
  156.  
  157.     /* If there are more arguments or the last thing is not DONE, show
  158.     usage */
  159.     if (t == argc || level)
  160.     {
  161.     fprintf (stderr, "FOR: Missing DONE (t=%d, argc=%d, level=%d)\n",
  162.         t, argc, level);
  163.     goto show_usage;
  164.     }
  165.  
  166.     /* Set the pointer to the last cmd */
  167.     last_cmd = t-1;
  168.  
  169.     /* If the last pattern is ";" (like in the bourne shell), ignore it */
  170.     if (argv[last_cmd][0] == ';' && !argv[last_cmd][1])
  171.     last_cmd --;
  172.  
  173.     /* If's ok to have no commands at all */
  174.     if (last_cmd < first_cmd)
  175.     return 0;
  176.  
  177.     /* Now execute the commands for each pattern */
  178.     for (t=first_pat; t<=last_pat && !status; t++)
  179.     {
  180.     len = (strlen (argv[t])+1)*2;
  181.     pat = AllocMem (len, MEMF_ANY);
  182.  
  183.     if (!pat)
  184.     {
  185.         fprintf (stderr, "FOR: Ran our of memory\n");
  186.         return 20;
  187.     }
  188.  
  189.     has_wild = ParsePatternNoCase (argv[t], pat, len);
  190.  
  191.     switch (has_wild)
  192.     {
  193.     case -1: /* Error in pattern */
  194.         fprintf (stderr, "FOR: Error parsing \"%s\":", argv[t]);
  195.         PrintFault (IoErr(), NULL);
  196.         status = 10;
  197.         break;
  198.  
  199.     case 0: /* No pattern, just a simple string */
  200.         if (!SetVar (var, argv[t], -1, GVF_LOCAL_ONLY))
  201.         {
  202.         fprintf (stderr, "FOR: Error setting %s to \"%s\":", var,
  203.             argv[t]);
  204.         PrintFault (IoErr(), "FOR: Error parsing \"%s\":");
  205.         status = 10;
  206.         }
  207.         else
  208.         status = execute_commands (last_cmd-first_cmd+1,
  209.             &argv[first_cmd]);
  210.         break;
  211.  
  212.     case 1: { /* Wildcards */
  213.         struct AnchorPath * ap;
  214.         LONG error;
  215.  
  216.         if (!(ap = AllocMem (ANCHORSIZE, MEMF_CLEAR)) )
  217.         {
  218.         fprintf (stderr, "FOR: Ran out of memory\n");
  219.         status = 10;
  220.         }
  221.         else
  222.         {
  223.         ap->ap_BreakBits = SIGBREAKF_CTRL_C;
  224.         ap->ap_Strlen     = FULLPATHSIZE;
  225.  
  226.         for (error=MatchFirst(argv[t],ap); !error && !status;
  227.             error=MatchNext(ap))
  228.         {
  229.             if (!SetVar (var, ap->ap_Buf, -1, GVF_LOCAL_ONLY))
  230.             {
  231.             fprintf (stderr, "FOR: Error setting %s to \"%s\":",
  232.                 var, argv[t]);
  233.             PrintFault (IoErr(), "FOR: Error parsing \"%s\":");
  234.             status = 10;
  235.             }
  236.             else
  237.             status = execute_commands (last_cmd-first_cmd+1,
  238.                 &argv[first_cmd]);
  239.         }
  240.  
  241.         if (error != ERROR_NO_MORE_ENTRIES)
  242.         {
  243.             PrintFault (error, "FOR");
  244.             status = 10;
  245.         }
  246.  
  247.         FreeMem (ap, ANCHORSIZE);
  248.         }
  249.         break; }
  250.     }
  251.  
  252.     FreeMem (pat, len);
  253.     }
  254.  
  255.     return status;
  256. } /* for_command */
  257.  
  258. /* Execute a list of commands. Each command is separated by ";".
  259.     Commands may be grouped in () to form a sub-shell. Currently
  260.     this sub-shell just restores the current directory */
  261. int execute_commands (int argc, char ** argv)
  262. {
  263.     int t;
  264.     int status = 0;
  265.     int first_arg, last_arg;
  266.     int level;
  267.     BPTR cd, orig;
  268.  
  269.     /* Check all arguments. Note that this is not the only
  270.     place where t might change */
  271.     for (t=0; t<argc && !status; t++)
  272.     {
  273.     /* Find out where we are */
  274.     if (argv[t][0] == '(' && !argv[t][1]) /* Subshell */
  275.     {
  276.         if ((cd = Lock ("", SHARED_LOCK)))
  277.         {
  278.         /* Find all commands which are in the subshell */
  279.         first_arg = ++t;
  280.         level = 0;
  281.  
  282.         while (t<argc)
  283.         {
  284.             if (argv[t][0] == '(' && !argv[t][1])
  285.             level ++;
  286.             else if (argv[t][0] == ')' && !argv[t][1])
  287.             {
  288.             if (!level)
  289.                 break;
  290.  
  291.             level --;
  292.             }
  293.  
  294.             t ++;
  295.         }
  296.  
  297.         if (t != argc)
  298.         {
  299.             last_arg = t-1;
  300.  
  301.             /* Remeber the current dir */
  302.             orig = CurrentDir (cd);
  303.  
  304.             /* Execute the commands of the sub-shell */
  305.             status = execute_commands (last_arg-first_arg+1,
  306.             &argv[first_arg]);
  307.  
  308.             /* Come back to the original dir */
  309.             UnLock (CurrentDir (orig));
  310.         }
  311.         else
  312.         {
  313.             fprintf (stderr, "FOR: Missing ) in sub shell\n");
  314.             status = 10;
  315.         }
  316.         }
  317.         else
  318.         {
  319.         PrintFault (IoErr(), "FOR: Cannot lock current dir");
  320.         status = 10;
  321.         }
  322.     }
  323.     else if (!strcmpi (argv[t], "CD")) /* cd command */
  324.     {
  325.         /* ignore the CD */
  326.         t ++;
  327.  
  328.         /* Change the dir */
  329.         status = cd_command (t!=argc ? argv[t] : NULL);
  330.     }
  331.     else /* Normal command */
  332.     {
  333.         first_arg = t;
  334.  
  335.         while (t<argc && !(argv[t][0] == ';' && !argv[t][1]))
  336.         t ++;
  337.  
  338.         last_arg = t-1;
  339.  
  340.         status = execute_command (last_arg-first_arg+1, &argv[first_arg]);
  341.     }
  342.     }
  343.  
  344.     return status;
  345. } /* execute_commands */
  346.  
  347. int cd_command (char * path)
  348. {
  349.     BPTR lock;
  350.     char * realpath;
  351.  
  352.     if (path)
  353.     {
  354.     realpath = replace_vars (path);
  355.  
  356.     if (show_debug)
  357.         printf ("CD (%s)\n", realpath);
  358.  
  359.     if (!(lock = Lock (realpath, SHARED_LOCK)) )
  360.     {
  361.         fprintf (stderr, "FOR: Cannot Lock \"%s\"\n", realpath);
  362.         free (realpath);
  363.         PrintFault (IoErr(), NULL);
  364.         return 10;
  365.     }
  366.  
  367.     free (realpath);
  368.     UnLock (CurrentDir (lock));
  369.     }
  370.     else
  371.     {
  372.     if (!(lock = Lock ("", SHARED_LOCK)) )
  373.     {
  374.         fprintf (stderr, "FOR: Cannot Lock current dir");
  375.         PrintFault (IoErr(), NULL);
  376.         return 10;
  377.     }
  378.  
  379.     realpath = malloc (4096);
  380.  
  381.     NameFromLock (lock, realpath, 4096);
  382.     puts (realpath);
  383.     free (realpath);
  384.     }
  385.  
  386.     return 0;
  387. } /* cd_command */
  388.